/**
 * Copyright (c) 2012-2014 All Rights Reserved.
 */
package com.easy.framwork.utils;

import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.easy.framwork.exceptions.EasyException;
import com.easy.framwork.exceptions.IllegalArgException;

/**
 * 
 * @author wy
 * @version v 0.1 2014-1-7 下午9:14:43 wy Exp $
 */
public class DateUtils {

    /**
     * 格式化字符串
     * 
     * @param str
     * @param parsePatterns
     * @return
     * @throws ParseException
     */
    public static Date parseDateStrictly(String str, String[] parsePatterns) {
        try {
            return parseDateWithLeniency(str, parsePatterns, false);
        }
        catch (ParseException e) {
            throw new EasyException("格式化异常", e);
        }
    }

    /**
     * 
     * @param str the date to parse, not null
     * @param parsePatterns the date format patterns to use, see
     *            SimpleDateFormat, not null
     * @param lenient Specify whether or not date/time parsing is to be lenient.
     * @return the parsed date
     * @throws IllegalArgumentException if the date string or pattern array is
     *             null
     * @throws ParseException if none of the date patterns were suitable
     * @see java.util.Calender#isLenient()
     */
    private static Date parseDateWithLeniency(String str, String[] parsePatterns, boolean lenient)
                                                                                                  throws ParseException {
        if (str == null || parsePatterns == null) {
            throw new IllegalArgException("Date and Patterns must not be null");
        }

        SimpleDateFormat parser = new SimpleDateFormat();
        parser.setLenient(lenient);
        ParsePosition pos = new ParsePosition(0);
        for (int i = 0; i < parsePatterns.length; i++) {

            String pattern = parsePatterns[i];

            // LANG-530 - need to make sure 'ZZ' output doesn't get passed to SimpleDateFormat
            if (parsePatterns[i].endsWith("ZZ")) {
                pattern = pattern.substring(0, pattern.length() - 1);
            }

            parser.applyPattern(pattern);
            pos.setIndex(0);

            String str2 = str;
            // LANG-530 - need to make sure 'ZZ' output doesn't hit SimpleDateFormat as it will ParseException
            if (parsePatterns[i].endsWith("ZZ")) {
                int signIdx = indexOfSignChars(str2, 0);
                while (signIdx >= 0) {
                    str2 = reformatTimezone(str2, signIdx);
                    signIdx = indexOfSignChars(str2, ++signIdx);
                }
            }

            Date date = parser.parse(str2, pos);
            if (date != null && pos.getIndex() == str2.length()) {
                return date;
            }
        }
        throw new ParseException("Unable to parse the date: " + str, -1);
    }

    /**
     * Index of sign charaters (i.e. '+' or '-').
     * 
     * @param str The string to search
     * @param startPos The start position
     * @return the index of the first sign character or -1 if not found
     */
    private static int indexOfSignChars(String str, int startPos) {
        int idx = StringUtils.indexOf(str, '+', startPos);
        if (idx < 0) {
            idx = StringUtils.indexOf(str, '-', startPos);
        }
        return idx;
    }

    /**
     * Reformat the timezone in a date string.
     * 
     * @param str The input string
     * @param signIdx The index position of the sign characters
     * @return The reformatted string
     */
    private static String reformatTimezone(String str, int signIdx) {
        String str2 = str;
        if (signIdx >= 0 && signIdx + 5 < str.length()
            && Character.isDigit(str.charAt(signIdx + 1))
            && Character.isDigit(str.charAt(signIdx + 2)) && str.charAt(signIdx + 3) == ':'
            && Character.isDigit(str.charAt(signIdx + 4))
            && Character.isDigit(str.charAt(signIdx + 5))) {
            str2 = str.substring(0, signIdx + 3) + str.substring(signIdx + 4);
        }
        return str2;
    }

}
